package com.benew.ntt.xseval.sdk

import android.content.Context
import com.benew.ntt.evaluate.constant.EvalConst
import com.benew.ntt.evaluate.constant.EvalConst.config
import com.benew.ntt.evaluate.constant.EvalError
import com.benew.ntt.evaluate.constant.EvalType
import com.benew.ntt.evaluate.listener.IEvalSDK
import com.benew.ntt.evaluate.sdk.EvalSDKConfig
import com.benew.ntt.evaluate.sdk.EvalSDKEntity
import com.benew.ntt.evaluate.sdk.EvalSDKHandler
import com.benew.ntt.evaluate.sdk.IEvalSDKListener
import com.benew.ntt.xseval.constant.XSEvalConst
import com.benew.ntt.xseval.utils.AuthUtils
import com.benew.ntt.xseval.utils.RhymeUtils
import com.blankj.utilcode.util.GsonUtils
import com.blankj.utilcode.util.ThreadUtils
import com.blankj.utilcode.util.ToastUtils
import com.blankj.utilcode.util.Utils
import com.constraint.CoreProvideTypeEnum
import com.constraint.OffLineSourceEnum
import com.constraint.ResultBody
import com.ntt.core.nlogger.NLogger
import com.tencent.mmkv.MMKV
import com.xs.SingEngine
import com.xs.impl.AudioCreateCallback
import com.xs.impl.AudioErrorCallback
import com.xs.impl.OnRealTimeResultListener
import com.xs.impl.WarrantIdNeedUpdateCallback
import org.json.JSONException
import org.json.JSONObject

/**
 * 先声口语评测管理器
 */
class XSEvalSDK : IEvalSDK {
    val TAG = javaClass.simpleName

    var mSingEngine: SingEngine? = null
    var mEvalHandler: EvalSDKHandler? = null
    var mEvalListeners: MutableSet<IEvalSDKListener>? = null

    //拿WarrantId错误次数
    private var mWarrantIdErrorCount = 0

    fun getSingEngine(): SingEngine? {
        return this.mSingEngine
    }

    override fun init(
        context: Context,
        evalListeners: MutableSet<IEvalSDKListener>?,
        evalHandler: EvalSDKHandler?
    ) {
        MMKV.initialize(context)
        mEvalListeners = evalListeners
        this.mEvalHandler = evalHandler
        try {
            NLogger.d(TAG, "开始评测初始化")
            mSingEngine = SingEngine.newInstance(context)
            mSingEngine?.setListener(onResultListener)
            mSingEngine?.wavPath = EvalConst.getRecordFilePath()
            mSingEngine?.setUserNativeUnZipPath(XSEvalConst.EVALUATE_OFFLINE_RES)
            mSingEngine?.setAudioErrorCallback(onAudioErrorCallback)
            mSingEngine?.setWarrantIdNeedUpdateCallback(warrantIdNeedUpdateCallback)
            mSingEngine?.setSaveAudio(1)
            mSingEngine?.setServerAPI(XSEvalConst.ORAL_API)
            mSingEngine?.switchLog(true, true)
            mSingEngine?.setAudioCreateCallback(audioCreateCallback)
            mSingEngine?.setOpenVad(true, "vad.0.1.bin")
            mSingEngine?.setFrontVadTime((4000 * 1.5).toLong())
            mSingEngine?.setBackVadTime((1500 * 2.5).toLong())
            mSingEngine?.setLogLevel(4)
            mSingEngine?.setServerTimeout(10L)
            //设置评测语言（针对离线评测）
            mSingEngine?.setOffLineSource(OffLineSourceEnum.SOURCE_BOTN)
            //设置离线资源名称
            mSingEngine?.setNativeZip("xiansheng.zip")
            //在线失败后,是否自动转离线
            mSingEngine?.setEnableContonative(1)
            mSingEngine?.switchLog(true, true)
            val cfgInit =
                mSingEngine?.buildInitJson(XSEvalConst.ORAL_APP_KEY, XSEvalConst.ORAL_SECRET_KEY)
            mSingEngine?.setNewCfg(cfgInit)
            AuthUtils.init(this)
            AuthUtils.setServerInfoType(mSingEngine, false)
            AuthUtils.setAuthInfo() //设置鉴权信息
            mSingEngine?.createEngine()
            AuthUtils.refreshWarrantId()
        } catch (e: Exception) {
            e.printStackTrace()
            NLogger.e(TAG, "评测初始化失败:" + e.message)
            mSingEngine = null
        }
    }

    private var warrantIdNeedUpdateCallback = WarrantIdNeedUpdateCallback {
        NLogger.d(TAG, "评测鉴权需要更新：onWarrantIdNeedUpdate")
        AuthUtils.getWarrantId()
    }

    private val onResultListener: OnRealTimeResultListener = object : OnRealTimeResultListener {
        override fun onRealTimeEval(jsonObject: JSONObject?) {
            NLogger.d(TAG, "评测实时反馈！！！！！！")
            mEvalHandler?.sendEvalProgress(jsonObject?.toString())

        }

        override fun onBegin() {
            NLogger.d(TAG, "评测开始了！！！！！！")
            mEvalHandler?.sendStartRecord()
        }

        override fun onResult(jsonObject: JSONObject?) {
            NLogger.d(TAG, "评测返回结果！！！！！！", jsonObject ?: "result is null")
            mEvalHandler?.sendResult(jsonObject?.toString())
        }

        override fun onEnd(resultBody: ResultBody?) {
            if (resultBody != null) {
                val code = resultBody.code
                NLogger.d(TAG, "评测结束！！！！！！！！返回码=" + code + ";错误" + resultBody.message + "!!!")
                if (code <= 0 || code == 70010) return //70010删除引擎失败

                val message = if (code == 16386) {
                    "网络异常哦！"
                } else {
                    resultBody.message
                }
                mEvalHandler?.sendError(message, code)
                if (code == 41030 || code == 70017) { //41030鉴权失败,70017warrantId过期
                    mWarrantIdErrorCount++
                    if (mWarrantIdErrorCount >= 2) {
                        if (mSingEngine != null) {
                            //两次获取评测warrantId失败，就转成离线
                            mSingEngine!!.setServerType(CoreProvideTypeEnum.NATIVE)
                            if (code == 70017) { //70017需要把warrantId设为空
                                mSingEngine!!.setAuthInfo(null, 0)
                            }
                        }
                    } else {
                        AuthUtils.getWarrantId()
                    }
                } else if (code == 70012) { //本次录音还未停止，可提示用户稍后再开始下一次录音。
                    reset()
                } else if (code == 60015) { //认证失败
                    reset()
                } else if (code == 42003) { //客户端发送请求的顺序出错
                    reset()
                }
            } else {
                NLogger.d(TAG, "评测结束！！！！！！！！")
            }
        }

        override fun onUpdateVolume(i: Int) {

        }

        override fun onFrontVadTimeOut() {
            NLogger.d(TAG, "评测前置超时了！！！！！！！！")
            mEvalHandler?.sendTimeOut()
        }

        override fun onBackVadTimeOut() {

        }

        override fun onRecordingBuffer(bytes: ByteArray, i: Int) {
            NLogger.d(TAG, "评测录音中！！！！！！")
            mEvalHandler?.recordOfByte(bytes, i, i, 0.0)

        }

        override fun onRecordLengthOut() {
            NLogger.d(TAG, "评测录音太长！！！！！！")
            mEvalHandler?.sendError("评测录音太长!", EvalError.ERROR_3)
        }

        override fun onReady() {
            NLogger.d(TAG, "评测引擎初始化成功！！！！！！")
            mEvalListeners?.forEach {
                it.onReady()
            }
        }

        override fun onPlayCompeleted() {

        }

        override fun onRecordStop() {
            NLogger.d(TAG, "评测录音停止！！！！！！")
            mEvalHandler?.sendRecordEnd()
        }
    }

    private val onAudioErrorCallback = AudioErrorCallback { i: Int ->
        NLogger.e(TAG, "录音器初始化错误")
        ToastUtils.showLong("录音器初始化错误:$i")
    }

    private var audioCreateCallback = AudioCreateCallback { s ->
        NLogger.d(TAG, "评测音频文件生成：$s")
        mEvalHandler?.sendRecordFile(s)
    }

    fun reset() {
        NLogger.d(TAG, "reset 重置评测")
        if (mSingEngine != null) {
            mSingEngine!!.deleteSafe()
            mSingEngine = null
        }
        init(Utils.getApp(), mEvalListeners, mEvalHandler)
    }

    /**
     * 内容韵母转换
     */
    private fun contentRhymeCovert(type: String?, content: String?): String? {
        return if (type != null && type.contains("cn.")) { //中文类型的就进行韵母转换
            RhymeUtils.covertRhyme(content) ?: ""
        } else content
    }

    override fun startEval(entity: EvalSDKEntity) {
        if (mSingEngine == null) {
            mEvalHandler?.sendError(null, EvalError.ERROR_1)
            reset()
            NLogger.d(TAG, "执行评测 实例为空")
            return
        }
        try {
            val refText = contentRhymeCovert(convertType(entity.type), entity.content)
            val jsonObject = JSONObject()
            jsonObject.put("coreType", convertType(entity.type))
            jsonObject.put("refText", refText)
            jsonObject.put("rank", 100) //总分
            jsonObject.put("precision", 1)
            jsonObject.put("rateScale", 1.1f) //打分宽松度
            jsonObject.put("phdet", 1)
            val startCfg =
                mSingEngine!!.buildStartJson(EvalConst.config?.getDeviceId() ?: "", jsonObject)
            mSingEngine!!.setStartCfg(startCfg)
            mSingEngine!!.start()
            NLogger.d(TAG, "执行评测 executeOralStart", GsonUtils.toJson(entity))
        } catch (e: JSONException) {
            NLogger.e(TAG, "开始评测异常：" + e.message)
            e.printStackTrace()
        }
    }

    override fun stopRecord() {
        try {
            mSingEngine?.stop()
        } catch (e: Exception) {
            NLogger.e(TAG, "停止录音异常：" + e.message)
        }
    }

    override fun cancelEval() {
        try {
            mSingEngine?.cancel()
        } catch (e: Exception) {
            NLogger.e(TAG, "取消评测异常：" + e.message)
        }
    }

    override fun deleteEval() {
        try {
            mSingEngine?.delete()
            mSingEngine = null
        } catch (e: Exception) {
            NLogger.e(TAG, "取消评测异常：" + e.message)
        }
    }

    override fun convertType(type: String?): String? {
        return when (type) {
            EvalType.EN -> {
                "en.sent.score"
            }
            EvalType.ZH_CHS -> {
                "cn.sent.score"
            }
            EvalType.PHONETICIZE -> {
                "cn.sent.score"
            }
            EvalType.CN_PRED -> {
                "cn.pred.score"
            }
            EvalType.EN_WORD -> {
                "en.word.score"
            }
            else -> {
                type
            }
        }
    }

}